package org.ims.inv.web.action.project;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.ims.inv.model.flow.ModelFlowDef;
import org.ims.inv.model.flow.ModelFlowTemplate;
import org.ims.inv.model.flow.confer.ModelFlowConfer;
import org.ims.inv.model.project.ModelProject;
import org.ims.inv.model.project.ModelProjectConference;
import org.ims.inv.model.project.ModelProjectProcess;
import org.ims.inv.model.system.ModelAppUser;
import org.ims.inv.web.util.ContextUtil;

import cn.trymore.core.util.UtilCollection;
import cn.trymore.core.util.UtilString;
import cn.trymore.core.web.paging.PaginationSupport;
import cn.trymore.core.web.paging.PagingBean;

/**
 * Action: 项目审批 (初审, 复审, 过会)
 * 
 * @author Jeccy.Zhao
 *
 */
public class ProjectAuditAction
extends ProjectBaseAction
{
	/**
	 * The LOGGER
	 */
	private static final Logger LOGGER = Logger.getLogger(ProjectAuditAction.class);
	
	/**
	 * 初审
	 */
	private final String PHASE_FIRST_TRIAL = "trial";
	
	/**
	 * 复审
	 */
	private final String PHASE_RE_TRIAL = "review";
	
	/**
	 * 过会
	 */
	private final String PHASE_CONFERENCE = "conference";
	
	/**
	 * 过会预审
	 */
	private final String PHASE_CONFERENCE_PREAUDIT = "conference_preaudit";
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 项目初审 & 项目复审
	 */
	public ActionForward pageProjectAuditIndex (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			// 获取审批环节
			String phase = request.getParameter("phase");
			
			if (UtilString.isNotEmpty(phase))
			{
				ModelProject formEntity = (ModelProject) form;
				
				// 项目负责人
				String projectManagerName = request.getParameter("mgr.username");
				if (UtilString.isNotEmpty(projectManagerName))
				{
					ModelAppUser manager = new ModelAppUser();
					manager.setUsername(projectManagerName);
					formEntity.setProjectManager(manager);
				}
				
				// 行业类别
				String projectTypeId = request.getParameter("projectTypeId");
				if (UtilString.isNotEmpty(projectTypeId))
				{
					formEntity.setProjectType(this.serviceAppDictionary.get(projectTypeId));
				}
				
				PagingBean pagingBean = this.getPagingBean(request);
				PaginationSupport<ModelProject> pagingData = null;
				
				if (PHASE_FIRST_TRIAL.equalsIgnoreCase(phase))
				{
					// 初审
					pagingData = this.serviceProject.getFirstTrialProjects(formEntity, pagingBean);
				}
				else if (PHASE_RE_TRIAL.equalsIgnoreCase(phase))
				{
					// 复审
					pagingData = this.serviceProject.getRetrialProjects(formEntity, pagingBean);
				}
				else if (PHASE_CONFERENCE_PREAUDIT.equalsIgnoreCase(phase))
				{
					// 过会预审
					List<ModelFlowConfer> conferences = this.serviceWorkFlow.getServiceFlowConfer().getAll();
					if (UtilCollection.isNotEmpty(conferences))
					{
						for (ModelFlowConfer conference : conferences)
						{
							// 获取需要审批的数量
							conference.setAuditNum(this.getNumProjectForConferencePreAudit(conference.getId()));
						}
					}
					
					request.setAttribute("nodesForConferencePreAudit", conferences);
				}
				else if (PHASE_CONFERENCE.equalsIgnoreCase(phase))
				{
					// 获取当前激活模板并从中获取需要过会的环节
					
					ModelFlowDef def = 
						this.serviceWorkFlow.getServiceFlowDefinition().getCurrentAppliedDefinition();
					
					if (def != null)
					{
						List<ModelFlowTemplate> nodesForConference = new ArrayList<ModelFlowTemplate>();
						Set<ModelFlowTemplate> templates = def.getTemplates();
						if (UtilCollection.isNotEmpty(templates))
						{
							for (ModelFlowTemplate template : templates)
							{
								if (template.getConferenceFlag() == 1)
								{
									// 获取需要审批的项目数
									template.setAuditNum(
											this.getNumProjectForConference(template.getId()));
									
									nodesForConference.add(template);
								}
							}
						}
						
						request.setAttribute("nodesForConference", nodesForConference);
					}
				}
				else
				{
					return ajaxPrint(response, getErrorCallback("未知的审批环节..."));
				}
				
				request.setAttribute("datagrid", pagingData);
				request.setAttribute("formEntity", formEntity);
				
				request.setAttribute("module", "audit");
				
				// 获取项目所属行业
				request.setAttribute("dictInds", this.getDictionariesByType("DICT_PRO_INDUSTRY"));
				
				this.outWritePagination(request, pagingBean, pagingData);
				this.outWriteAllParameters(request);
				
				return mapping.findForward("page.project.audit.index");
			}
			else
			{
				return ajaxPrint(response, getErrorCallback("未知请求参数..."));
			}
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
		
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 过会预审审批
	 */
	public ActionForward actionAuditProjectConference (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			String id = request.getParameter("id");
			
			if (this.isObjectIdValid(id))
			{
				ModelProjectConference entity = this.serviceProjectConference.get(id);
				if (entity != null)
				{
					String auditState = request.getParameter("auditState");
					String auditComments = request.getParameter("auditComments");
					
					entity.setAuditStatus(Integer.valueOf(auditState));
					entity.setAuditComments(auditComments);
					entity.setAuditor(ContextUtil.getCurrentUser());
					entity.setAuditTime(new Date());
					
					this.serviceProjectConference.save(entity);
					
					ModelProject project = entity.getProcess().getProject();
					
					// 更新项目审批流程环节
					ModelProjectProcess process = entity.getProcess();
					if (Integer.valueOf(auditState).equals(
							ModelProjectProcess.EProjectDependFlowAuditState.PASS.getValue()))
					{
						// 通过
						process.setDependedFlowAuditStatus(
							ModelProjectProcess.EProjectDependFlowAuditState.PASS.getValue());
						
						this.serviceProjectProcess.save(process);
					}
					else
					{
						// 否决, 回退至上一个审批环节
						int start = -1;
						boolean rolled = false;
						while (!rolled)
						{
							ModelProjectProcess previousProcess = project.getProcessByOffset(start);
							
							if (previousProcess != null)
							{
								if (previousProcess.getAuditState().equals(ModelProjectProcess.EProjectAuditState.PASS.getValue()))
								{
									// 上一环节审核通过, 则直接更改当前环节为材料上交状态
									project.setProjectStatus(ModelProject.EProjectStatus.TOPOST.getValue());
									project.setCurrentProcess(project.getProcessByOffset(start + 1));
									rolled = true;
								}
								else
								{
									previousProcess.setAuditor(null);
									previousProcess.setAuditComments(null);
									previousProcess.setAuditDate(null);
									
									if (previousProcess.getSequence() == 1 || 
											!previousProcess.getAuditState().equals(ModelProjectProcess.EProjectAuditState.IGNORED.getValue()))
									{
										// 被忽略的环节或者是第一个环节
										project.setCurrentProcess(previousProcess);
										project.setProjectStatus(ModelProject.EProjectStatus.TOPOST.getValue());
										rolled = true;
									}
									
									previousProcess.setAuditState(null);
								}
								
								this.serviceProjectProcess.save(previousProcess);
								start = start - 1;
							}
							else
							{
								break;
							}
							
						}
						
						this.serviceProject.save(project);
					}
					
					// 事件记录
					this.serviceProjectEvent.traceEvent(project, 
						EVENT_CONFERENCE_PREAUDIT, 
						null, 
						(Integer.valueOf(auditState).equals(
								ModelProjectProcess.EProjectDependFlowAuditState.PASS.getValue()) ? "通过" : "未通过") + 
						"`" + entity.getProcess().getDependedFlow().getNodeTitle() + "`" + 
							(UtilString.isNotEmpty(auditComments) ? (":" + auditComments) : "") 
					);
					
					// 服务器推送至客户端.
					this.getMessagePush().pushMessage(
						this.getAllUserIds(),
						scriptMessageNotify, 
						"menu_item_project_preconfer",
						-1
					);
					
					if (Integer.valueOf(auditState).equals(ModelProjectProcess.EProjectDependFlowAuditState.PASS.getValue()))
					{
						// 服务器推送至客户端.
						this.getMessagePush().pushMessage(
							this.getAllUserIds(),
							scriptMessageNotify, 
							"menu_item_project_confer",
							1
						);
					}
					else
					{
						// 服务器推送至客户端.
						this.getMessagePush().pushMessage(
								project.getProjectRelevantPersonIds(),
							scriptMessageNotify, 
							"menu_item_project_track",
							1
						);
					}
					
					return ajaxPrint(response, 
							getSuccessCallback("流程审批成功.", CALLBACK_TYPE_CLOSE, CURRENT_NAVTABID, null, false));
				}
				else
				{
					return ajaxPrint(response, getErrorCallback("数据实体不存在."));
				}
			}
			else
			{
				return ajaxPrint(response, getErrorCallback("未知的请求参数."));
			}
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when operating page", e);
			return ajaxPrint(response, getErrorCallback("过会预审审批失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 流程审批
	 */
	public ActionForward actionAuditProjectProcess (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			String projectId = request.getParameter("projectId");
			String auditState = request.getParameter("auditState");
			
			if (UtilString.isNotEmpty(projectId, auditState))
			{
				ModelProject entity = this.serviceProject.get(projectId);
				if (entity != null)
				{
					int state = Integer.valueOf(auditState);
					
					ModelProjectProcess processNode = entity.getCurrentProcess();
					if (processNode == null)
					{
						return ajaxPrint(response, getErrorCallback("未知的审批流程."));
					}
					
					if (ModelProjectProcess.EProjectAuditState.PASS.getValue().equals(state))
					{
						// 通过
						this.auditHandleOnPass(entity);
					}
					else if (ModelProjectProcess.EProjectAuditState.RETURNED.getValue().equals(state))
					{
						// 退回
						this.auditHandleOnReturn(entity);
						
						// 调整被退回的环节
						String returnProcessId = request.getParameter("returnProcessId");
						ModelProjectProcess toProcess = this.serviceProjectProcess.get(returnProcessId);
						if (toProcess != null)
						{
							// 重置被退回的环节信息
							toProcess.setMaterialStatus(ModelProjectProcess.EProjectMaterialStatus.TODO.getValue());
							toProcess.setAuditState(null);
							toProcess.setAuditDate(null);
							toProcess.setAuditComments(null);
							
							for (ModelProjectProcess proc : entity.getProcessForms())
							{
								if (proc.getSequence() > toProcess.getSequence() && 
										proc.getSequence() <= entity.getCurrentProcess().getSequence())
								{
									proc.setMaterialStatus(ModelProjectProcess.EProjectMaterialStatus.TODO.getValue());
									proc.setAuditState(null);
									proc.setAuditDate(null);
									proc.setAuditComments(null);
									
									this.serviceProjectProcess.save(proc);
								}
							}
							
							entity.setCurrentProcess(toProcess);
						}
					}
					else if (ModelProjectProcess.EProjectAuditState.REJECTED.getValue().equals(state))
					{
						// 否决
						this.auditHandleOnReject(entity);
					}
					else 
					{
						return ajaxPrint(response, getErrorCallback("未知审批状态."));
					}
					
					String menuItemId = ""; 
					if (processNode.getSequence() == 1)
					{
						// 初审
						menuItemId = "menu_item_project_trial";
					}
					else if (processNode.getSequence() == 2)
					{
						// 复审
						menuItemId = "menu_item_project_review";
					}
					else
					{
						// 过会
						menuItemId = "menu_item_project_confer";
					}
					
					String currentProcessName = processNode.getNodeTitle();
					if (!ModelProjectProcess.EProjectAuditState.RETURNED.getValue().equals(state))
					{
						// 针对退回操作, 不进行节点更新, 只记录日志..
						if (processNode != null)
						{
							processNode.setAuditComments(request.getParameter("auditComments"));
							processNode.setAuditDate(new Date());
							processNode.setAuditor(ContextUtil.getCurrentUser());
							processNode.setAuditState(state);
							this.serviceProjectProcess.save(processNode);
						}
						
						// 服务器推送至客户端.
						this.getMessagePush().pushMessage(
							this.getAllUserIds(),
							scriptMessageNotify, 
							menuItemId,
							-1
						);
						
						// 审批已结束...
						if (entity.getCurrentProcess() == null)
						{
							// 服务器推送至客户端.
							this.getMessagePush().pushMessage(
								entity.getProjectRelevantPersonIds(),
								scriptMessageNotify, 
								"menu_item_project_track",
								-1
							);
						}
					}
					else
					{
						// 重置审批环节已上交材料标志..
						entity.getCurrentProcess().setMaterialStatus(
								ModelProjectProcess.EProjectMaterialStatus.TODO.getValue());
						this.serviceProjectProcess.save(entity.getCurrentProcess());
						
						// 服务器推送至客户端.
						this.getMessagePush().pushMessage(
							this.getAllUserIds(),
							scriptMessageNotify, 
							menuItemId,
							-1
						);
					}
					
					// 保存项目
					this.serviceProject.save(entity);
					
					// 记录项目审批事件
					if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.RETURNED.getValue()))
					{
						this.serviceProjectEvent.traceEvent(entity, 
							currentProcessName, 
							state, 
							"退回至`" + entity.getCurrentProcess().getNodeTitle() + "`材料提交" + 
								(UtilString.isNotEmpty(request.getParameter("auditComments")) ? 
									(":" + request.getParameter("auditComments")) : "") 
						);
					}
					else
					{
						this.serviceProjectEvent.traceEvent(entity, 
								currentProcessName, state, request.getParameter("auditComments"));
					}
					
					return ajaxPrint(response, 
							getSuccessCallback("流程审批成功.", CALLBACK_TYPE_CLOSE, CURRENT_NAVTABID, null, false));
				}
				else
				{
					return ajaxPrint(response, getErrorCallback("数据实体不存在."));
				}
			}
			else
			{
				return ajaxPrint(response, getErrorCallback("未知的请求参数."));
			}
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when operating page", e);
			return ajaxPrint(response, getErrorCallback("项目审批失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * 审批通过后的项目处理
	 * 
	 * @param entity
	 */
	private void auditHandleOnPass (ModelProject entity)
	{
		ModelProjectProcess nextProcessNode = entity.getProcessByOffset(1);
		if (nextProcessNode != null)
		{
			entity.setCurrentProcess(nextProcessNode);
			
			if (nextProcessNode.getMaterialStatus().equals(
					ModelProjectProcess.EProjectMaterialStatus.POSTED.getValue()))
			{
				// 检测下一环节已经处于‘材料已提交’的状态, 置下一环节项目状态为"审批中"
				entity.setProjectStatus(ModelProject.EProjectStatus.APPROVING.getValue());
			}
			else
			{
				// 检测下一环节已经处于‘材料尚未提交’的状态, 置下一环节项目状态为"提交材料"
				entity.setProjectStatus(ModelProject.EProjectStatus.TOPOST.getValue());
			}
		}
		else
		{
			// 当前为最后一个节点
			entity.setCurrentProcess(null);
			// entity.setProcessForms(null);
			entity.setProjectStatus(ModelProject.EProjectStatus.APPROVED.getValue());
		}
	}
	
	/**
	 * 审批退回后的项目处理
	 * 
	 * @param entity
	 */
	private void auditHandleOnReturn (ModelProject entity)
	{
		// 退回提交材料环节
		entity.setProjectStatus(ModelProject.EProjectStatus.RETURNED.getValue());
	}
	
	/**
	 * 审批否决后的项目处理
	 * 
	 * @param entity
	 */
	private void auditHandleOnReject (ModelProject entity)
	{
		entity.setCurrentProcess(null);
		// entity.setProcessForms(null);
		entity.setProjectStatus(ModelProject.EProjectStatus.REJECTED.getValue());
	}
	
	public static Logger getLogger()
	{
		return LOGGER;
	}
	
}
